///////////////////////////////////////////////////////////////////////////////
////  (c) Chaichuk AU (chaichuk@mail.ru), 								   ////
////  2005, Chelyabinsk, NTC Privodnaya Tehnika (momentum@chel.surnet.ru)  ////
///////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>
#include <hw/pci.h>
#include <sys/mman.h>
#include <hw/inout.h>
#include <unistd.h>

#include "anybus_pci.h"
#include "color.h"

//#define DEBUG_ANYBUS_PCI_C

//----------------------------------------------------------------------------
int abs_pci_init_board (abs_pci_board_t* board, int pci_index)
{
	void					*device_handle;
	int						pci_handle;
	struct	pci_dev_info 	pci_info;
	int						len;
	abs_module_t			*abs = &board->abs_module;
	
    // Connect to the PCI server 
	#ifdef DEBUG_ANYBUS_PCI_C 
	printf ("pci_attcach ..\n"); fflush (stdout); delay (2); 
	#endif
    pci_handle = pci_attach (0);
    if (pci_handle == -1) {
        fprintf (stderr, "Unable to initialize PCI\n");
        return -1;
    }

    // Initialize the pci_dev_info structure 
    memset (&pci_info, 0, sizeof (pci_info));
    pci_info.VendorId = ANYBUS_DPM_VENDOR_ID;
    pci_info.DeviceId = ANYBUS_DPM_DEVICE_ID;

	#ifdef DEBUG_ANYBUS_PCI_C 
	printf ("device_attcach ..\n"); fflush (stdout); delay (2); 
	#endif
    device_handle = pci_attach_device (NULL, PCI_INIT_ALL, pci_index, &pci_info);
    if (device_handle == NULL) {
        fprintf (stderr, "Unable to locate device!\n");        
        return -1;
    }
    
    board->pci_index = pci_index;
    board->io_addr 	 = PCI_IO_ADDR  (pci_info.PciBaseAddress[1]);
    board->mem_addr	 = PCI_MEM_ADDR (pci_info.PciBaseAddress[2]);     	
    board->irq 		 = pci_info.Irq;
    
    len = 0x80;
	#ifdef DEBUG_ANYBUS_PCI_C 
	printf ("mmap_device_io ..\n"); fflush (stdout); delay (2); 
	#endif
  	board->iobase = mmap_device_io (len, board->io_addr);
  	if (board->iobase == MAP_DEVICE_FAILED) {
  		perror ("can't mmap_device_io");
  		return -1;
	}
	
    len = 0x80000;
	#ifdef DEBUG_ANYBUS_PCI_C 
	printf ("mmap_device_memory ..\n"); fflush (stdout);  delay (2); 
	#endif
    board->mem_ptr = (uint8_t*) mmap_device_memory (NULL, len, PROT_READ | PROT_WRITE | PROT_NOCACHE, 0, board->mem_addr);
    if (board->mem_ptr == MAP_FAILED) {
    	perror ("can't mmap_device_memory");
    	return -1;
	}

	abs->input_data_area_ptr 		= NULL;
	abs->output_data_area_ptr 		= NULL;
	abs->mailbox_input_area_ptr 	= board->mem_ptr + 0xC00;
	abs->mailbox_output_area_ptr 	= board->mem_ptr + 0xD20;
	abs->fieldbus_spec_area_ptr 	= board->mem_ptr + 0xE40;
	abs->control_register_area_ptr 	= board->mem_ptr + 0xFC0;
	abs->indic_register_rw_ptr 		= board->mem_ptr + 0xFFE;
	abs->indic_register_ro_ptr 		= board->mem_ptr + 0xFFF;	

	//printf ("intr_reg: %d\n", in16 (board->iobase + PLX_INTR_REG));	
	
	#ifdef DEBUG_ANYBUS_PCI_C 
	printf ("abs_init ..\n"); fflush (stdout);  delay (2); 
	#endif
	if (abs_init (abs) != 0) {
		fprintf (stdout, "%s", RED);
		fprintf (stdout, "anybus init failed (maybe already initialized)!");
		fprintf (stdout, "%s\n", SGR0);		
	}

	#ifdef DEBUG_ANYBUS_PCI_C 
	printf ("abs_request_fbctrl_area ..\n"); fflush (stdout);  delay (2); 
	#endif
	abs_request_fbctrl_area (abs);
	do abs_update_status (abs); while (!abs->fbctrl_area_free);
	if (board->mem_ptr [0xE78] == 1) {	// Extended DPRAM mode
		abs->input_data_area_ptr 	= board->mem_ptr + 0x000;
		abs->output_data_area_ptr 	= board->mem_ptr + 0x600;
	} else {							// Standart DPRAM mode
		printf ("Standart mode DPRAM\n");
		abs->input_data_area_ptr 	= board->mem_ptr + 0x800;
		abs->output_data_area_ptr 	= board->mem_ptr + 0xA00;
	}
	abs_release_fbctrl_area (abs);
	do abs_update_status (abs); while (abs->fbctrl_area_free);

	#ifdef DEBUG_ANYBUS_PCI_C 
	printf ("return 0 ..\n"); fflush (stdout);  delay (2); 
	#endif
	return 0;
}